Skip to main content

13 UART实验

串口数组和指针发送 串口中断接收

up的视频讲解: https://space.bilibili.com/1455872040

up视频里的实验代码: 👣串口实验代码

SerialPie串口助手测试例程: 📥串口助手测试代码

CH340驱动: 🔧CH340串口驱动安装

🔤串口重定向函数
#include <stdio.h>
// printf输出重定向
int fputc(int ch, FILE *f)
{
uint8_t temp = ch;
HAL_UART_Transmit(&huart1, &temp, 1, HAL_MAX_DELAY);
return ch;
}

// scanf / getchar 输入重定向
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, HAL_MAX_DELAY);
return ch;
}

✉️ UART通信实验原理​

图片

微控制器是采用的是 UART通信 而电脑采用的是 USB通信

  • UART与USB的物理连接 电平标准 以及数据帧的格式都存在区别
  • 所以就需要CH340将UART通信协议与USB通信协议 进行转化

我们需要注意到一个本质的问题是 这些传输的 01数据到底代表着什么意思?

图片

我们传的其实是 字符数据 什么是字符呢? 我们来看到这张ASCII表

  • 如果计算机判定为是字符数据 那他就会拿到每一帧里的8bit数据
  • 然后去这张ASCII表里面找到对应字符
  • 比如说 字母A对应的就是0100 0001的数据 用十进制表示就是65
  • 再比如说 这里的数字6 对应的就是0011 0110的数据 用十进制表示就是54
打印字符与非打印字符
  • 右边这一页 是打印字符 也就是具体可以在屏幕上显示的字符
  • 而左边的这一页 是非打印字符 也就是做一些控制功能用的 比如说键盘上的回车 ESC返回

1 💻串口数组/指针发送实验​

1.1 实验连接​

图片

1.2 实验原理​

图片

C语言中 Char 这个数据类型就代表着它存放的是一个字符 比如说这里的H 它本质上就是 将H对应的8位ASCII值写到RAM空间里面 但我们通常需要传输的是一串字符 比如说Hello 这时候我们就会用到 指针和数组这两种数据类型 来装这一串字符的ASCII值

数组

  • 比如说用下面的数组的话 那么CPU就会将这5个字母的ASCII值 依次 存放到RAM里面
  • 在结尾处还会加一个 \0表示字符串的结束
  • 所以Hello这个字符串 一共花了6个字节的RAM空间去装

指针

  • 而通过指针的方式 是这样Hello这里是一个常量数据 常量数据 在下载的时候就存放到flash里面的
  • 它就不会像数组一个一个一个的拿到RAM里面 而是将第一个字符的地址 存放到RAM里面
  • STM32是32位寻址 所以存的是32位也就是4个字节
指针和数组
  • 数组名p代表着是第一个元素的地址
  • 指针变量p的值也就是RAM里面存的地 址数据 而*p这个*是一个寻址的指令
图片

但up在这里还需要补充一点的是 在我们传数字的时候 往往传输的不是123这种常量数据 而是传输的像uinta float b这样的 变量

  • 对于这些变量 我们在写程序的时候还不知道它里面装的是什么

  • 这时候就需要调用到C语言的标准库的Printf 以及Sprintf函数 来帮我们将这些变量转化成字符

up简单说一下这两个函数的使用方法 在这个双引号里面的就是对应的字符内容 其中分为3部分

  • 直接写上的 是普通文本
  • 百分号后面的 是占位符 就是帮后面的变量占位置
  • \反斜杠后面的 是转义符 转义就是不是显示字符本身 而是其他意思
占位符和转义符
  • 占位符 百分号后面的字母也有区别 比如说变量a是uint8的类型就用%d占位 b是float浮点类型就用%f占位

  • 转义符 我们刚刚看到的ASCII表有打印和非打印两页 转义也就是将这个ASCII值对应非打印那一页 比如说这里的\r\n就是用于换行显示的意思

图片

这两种方式 我们都可以使用

printf 默认是将转化后的字符输出到控制台显示的 所以需要 串口重定向 然后再通过uart发送

sprintf把格式化后的字符写入指针指向的缓冲区,并不会修改指针本身。实际项目优先用snprintf指定缓冲区容量,检查返回值后再发送

1.3 CubeMX配置​

USART1选择Asynchronous,参数默认就好

图片

1.4 实验代码​

全局​

#include <stdio.h>

main()​

	char p1[] = "Hello";
char* p2 = "world\r\n";

while(1)里面​

		HAL_UART_Transmit(&huart1,p1,sizeof(p1)-1,1000);
HAL_UART_Transmit(&huart1,p2,strlen(p2),1000);
printf("Hello World\r\n");
HAL_Delay(50);

2 📨串口中断接收实验​

2.1 实验连接​

在发送实验接线基础上补接CH340 TXD到PA10;PA9接CH340 RXD,GND共地。

2.2 实验原理​

外设接满一个字节后触发回调,视频原代码重新开启接收,主循环根据rx判断。原例用于展示接收流程,不包含“消费后清除命令”的逻辑。

2.3 CubeMX配置​

配置UART时已包含发送

2.4 实验代码​

全局​

#include <stdio.h>

char rx = 0;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart1,&rx,1);
}

main()​

	HAL_UART_Receive_IT(&huart1,&rx,1);

while(1)里面​

		if(rx == '1')
{
printf("Hello World\r\n");
}

✅串口实验验收​

先发送固定Hello,再让电脑发送字符1观察回应。视频原代码会在rx保持为字符1期间持续打印。若乱码,检查波特率、数据位、串口号、系统时钟与共地;若完全无数据,先看TX引脚波形。

字符串数组可以使用sizeof减去末尾零字符;指针变量的sizeof是指针大小,不是字符串长度。snprintf返回值达到或超过缓冲区容量表示截断,不应把这个返回值原样当作可发送长度。

中断接收例程是低速单槽演示。要处理持续输入,增加环形缓冲及溢出统计,并处理HAL_UART_ErrorCallback中的ORE等错误,再按所用HAL版本恢复接收。